#!/bin/sh
# - nr_threads
# - test_memory_size
# - mode
# - test
# - nr_parallelism
# - size
# - stride
# - standalone
# - op

## lmbench is a suite of simple, portable, ANSI/C microbenchmarks for
## UNIX/POSIX. In general, it measures two key features: latency and
## bandwidth. lmbench is intended to give system developers insight into basic
## costs of key operations. Supports-
##
## Bandwidth benchmarks
##   Cached file read
##   Memory copy (bcopy)
##   Memory read
##   Memory write
##   Pipe
##   TCP
## Latency benchmarks
##   Context switching.
##   Networking: connection establishment, pipe, TCP, UDP, and RPC hot potato
##   File system creates and deletes.
##   Process creation.
##   Signal handling
##   System call overhead
##   Memory read latency
## Miscellanious
##   Processor clock rate calculation

. $LKP_SRC/lib/reproduce-log.sh
. $LKP_SRC/lib/debug.sh

# Run lmbench3 benchmark suit with all/hardware/os/development mode
# All mode: run all of the testcases
# Hardware mode: run a set of the hardware related testcases
# OS mode: run a set of the OS related testcases
# Development mode: run the pre-defined testcases
# Allow sheduler to place job
# Measure memory latency with a 128 byte stride
# Skip file system latency test
# Skip the disk tests
# Disable remote network latency/throuput test
# Use system detected CPU mhz for testing
# Use /var/tmp to store file as well as create and delete a large number of
# small files,
# Use /dev/tty to display output status information,
# Disable to send the test result to remote database

run_lmbench3_all()
{
	if [ "$is_performance_dashboard" = "true" ]; then
		run_by_make_rerun
	else
		run_by_make_results
	fi
}

run_by_make_rerun()
{
	cd scripts
	system_type=`./os`
	sed -i 's|^OS=.*|OS='"${system_type}"'|g' ../CONFIG.lmbench3
	mv ../bin/*/ ../bin/${system_type}/
	cp ../CONFIG.lmbench3 ../bin/${system_type}/CONFIG.$(hostname)
	env OS=${system_type}
	log_cmd ./results
}

run_by_make_results()
{
	log_eval "
	(
		echo $nr_threads
		echo 1
		echo $test_memory_size
		echo all
		echo yes
		echo yes
		echo
		echo
		echo
		[ $nr_threads -eq 1 ] &&
		{
			echo
			echo
		}
		echo no
	) | make results "
	wait
}

run_lmbench3_hardware()
{
	log_eval "
	(
		echo $nr_threads
		echo 1
		echo $test_memory_size
		echo hardware
		echo yes
		echo yes
		echo
		echo
		echo
		[ $nr_threads -eq 1 ] &&
		{
			echo
			echo
		}
		echo no
	) | make results "
	wait
}

run_lmbench3_os()
{
	log_eval "
	(
		echo $nr_threads
		echo 1
		echo $test_memory_size
		echo os
		echo yes
		echo
		echo
		echo
		[ $nr_threads -eq 1 ] && echo
		echo no
	) | make results "
}

run_lmbench3_development()
{
	local SYSCALL=no
	local SELECT=no
	local PROC=no
	local PAGEFAULT=no
	local FILE=no
	local MMAP=no
	local CTX=no
	local PIPE=no
	local UNIX=no
	local UDP=no
	local TCP=no
	local CONNECT=no
	local RPC=no
	local HTTP=no
	local BCOPY=no
	local MEM=no
	local OPS=no

	eval "$test=yes"

	sed -i '/lat_pagefault -P $SYNC_MAX $FILE/i [ -f $FILE ] || dd if=/dev/zero of=$FILE count=1 bs=1G' bin/"${system_type}"/lmbench
	log_eval "
	(
		echo $nr_threads
		echo 1
		echo $test_memory_size
		echo development

		echo $SYSCALL
		echo $SELECT
		echo $PROC
		echo $PAGEFAULT
		echo $FILE
		echo $MMAP
		echo $CTX
		echo $PIPE
		echo $UNIX
		echo $UDP
		echo $TCP
		echo $CONNECT
		echo $RPC
		echo $HTTP
		echo $BCOPY
		echo $MEM
		echo $OPS

		echo yes
		echo
		echo
		echo
		[ $nr_threads -eq 1 ] && echo
		echo no
	) | make results "

	wait
}

show_result()
{
	cat $BENCHMARK_ROOT/lmbench3/results/${system_type}/* || die "no test result found"
}

plot() {
hostname="$1"
gnuplot <<EOF
set terminal png medium size 1920,1080
set output "lmbench_result.png"
set title "Memory Latency Benchmark (Size=${size} Stride=${stride})"

set xlabel "Memory Depth (MB)"
set ylabel "Latency (ns)"

set grid

set style line 1 lc rgb '#0060ad' lt 1 lw 2 pt 7 ps 1   # --- blue

plot "${LMBENCH_RESULT}" using 1:2 with linespoints ls 1 smooth unique title "${hostname}"

EOF
}

if [ "${standalone}" != "1" ]; then
	test_memory_size=$((test_memory_size/1024/1024))

	# The bigger test memory range, the more accurate the results, but larger sizes
	# take somewhat longer to run the benchmark.
	# If test memory size greater than 10GB, bcopy test may take more than 30mins.
	# So limit the the maximum test memory size to 10GB.
	[ "$test_memory_size" -gt 10240 ] && test_memory_size=10240

fi


cd $BENCHMARK_ROOT/lmbench3 || {
	echo "ERROR: lmbench benchmark has not been installed yet"
	exit 1
}

[ ${os_arch} = "aarch64" ] && system_type="aarch64-linux-gnu"
[ ${os_arch} = "x86_64" ] && system_type="x86_64-pc-linux-gnu"

make 2>&1 || die "failed to build lmbench3"

if [ "${standalone}" != "1" ]; then

	case "$mode" in
		'all') run_lmbench3_all ;;
		'hardware') run_lmbench3_hardware ;;
		'os') run_lmbench3_os ;;
		'development') run_lmbench3_development ;;
		*) echo "invalid running mode:$mode in lmbench3" && exit 1
		esac

	show_result
else

	case "$test" in
		'lat_mem_rd')
			TEST_BIN_PATH="$(find bin/ -maxdepth 2 -name lat_mem_rd)"
			echo "Running memory load latency..."
			log_cmd ./${TEST_BIN_PATH} -P ${nr_parallelism} ${size} ${stride} > $TMP_RESULT_ROOT/lmbench3 2>&1 

			LMBENCH_RESULT="$TMP_RESULT_ROOT/extract-lmbench3"
			sed '1,2d' $TMP_RESULT_ROOT/lmbench3 > ${LMBENCH_RESULT}

			plot ${testbox}

			rm ${LMBENCH_RESULT}
			mv lmbench_result.png $TMP_RESULT_ROOT/lmbench_result.png
		;;
		'bw_mem')
			TEST_BIN_PATH="$(find bin/ -maxdepth 2 -name bw_mem)"
			echo "Running memory bandwitch test..."
			log_cmd ./${TEST_BIN_PATH} -P ${nr_parallelism} ${size} ${op} > $TMP_RESULT_ROOT/lmbench3 2>&1
		;;
		*) echo "invalid test:$test in lmbench3" && exit 1
	esac
fi
